package com.tian.service.impl.pay;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.tian.common.enums.PayStatusEnum;
import com.tian.common.exception.BusinessException;
import com.tian.common.factory.ApplicationContextFactory;
import com.tian.common.util.UserCacheUtil;
import com.tian.dto.user.ChargeUserLoginResDto;
import com.tian.dto.pay.PayNotifyTestReqDto;
import com.tian.entity.ChargePayOrder;
import com.tian.service.pay.PayBaseService;
import com.tian.service.pay.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * {@code @description:} 支付宝支付实现类
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024-11-23 15:29
 * {@code @version:} 1.0
 */
@Slf4j
@Service("aliPaymentService")
public class AliPaymentServiceImpl implements PaymentService {

    @Resource
    private AlipayConfig alipayConfig;

    @Override
    public String prepay(ChargePayOrder chargePayOrder, String msg, Boolean isTest) {
        //获取当前登录信息
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        try {
            AlipayTradePagePayResponse response = getAlipayTradePagePayResponse(chargePayOrder.getAmount(), msg, chargePayOrder.getOrderNo());
            if (!response.isSuccess()) {
                log.error("支付宝支付接口调用失败，错误信息：{}", response.getBody());
                throw new BusinessException("支付宝支付接口调用失败，请稍后重试");
            }
            return response.getBody();
        } catch (AlipayApiException e) {
            log.error("支付宝支付接口调用失败，错误信息：{}", e.getMessage());
            throw new BusinessException("支付宝支付接口调用失败，请稍后重试");
        }
    }

    private AlipayTradePagePayResponse getAlipayTradePagePayResponse(BigDecimal amount, String msg, String orderNo) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();

        model.setOutTradeNo(orderNo);
        model.setTotalAmount(amount.toString());
        model.setSubject(msg);
        model.setQrPayMode("1");
        model.setQrcodeWidth(100L);
        model.setProductCode("FAST_INSTANT_TRADE_PAY");

        request.setBizModel(model);

        return alipayClient.pageExecute(request, "POST");
    }

    /**
     * 支付结果通知 ----- 充值
     *
     * @param request
     * @param payNotifyTestReqDto
     */
    @Override
    public ResponseEntity<String> payNotify(HttpServletRequest request, PayNotifyTestReqDto payNotifyTestReqDto) {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        try {
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                String[] values = requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用
                valueStr = new String(valueStr.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                params.put(name, valueStr);
            }
            boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());
            /* 实际验证过程建议商户务必添加以下校验：
                1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
                2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
                3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
                4、验证app_id是否为该商户本身。
            */
            PayBaseService payBaseService = ApplicationContextFactory.getBean(PayBaseService.class);
            if (signVerified) {//验证成功
                //商户订单号
                String orderNo = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

                //支付宝交易号
                String trade_no = new String(request.getParameter("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

                //交易状态
                String trade_status = new String(request.getParameter("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

                if (trade_status.equals("TRADE_FINISHED")) {
                    //判断该笔订单是否在商户网站中已经做过处理
                    //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                    //如果有做过处理，不执行商户的业务程序
                    //注意：
                    //退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
                    return new ResponseEntity<>(HttpStatus.OK);
                } else if (trade_status.equals("TRADE_SUCCESS")) {
                    //注意：
                    //付款完成后，支付宝系统发送该交易状态通知
                    payBaseService.paySuccess(orderNo);
                    return new ResponseEntity<>(HttpStatus.OK);
                }else if (trade_status.equals("FAILED")){
                    //更新支付订单状态FAILED
                    payBaseService.payFailed(orderNo, PayStatusEnum.FAILED);
                    return new ResponseEntity<>(HttpStatus.OK);
                }
                log.info("支付宝支付结果通知支付状态未知，订单号：{},支付宝通知状态：{}", orderNo,trade_status);
                return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
            }
            log.error("支付宝支付结果通知验签失败");
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        } catch (Exception e) {
            log.error("支付宝支付结果通知验签失败", e);
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

}
